﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using BrightIdeasSoftware;
using NymphsLib.CommonUtilities;
using NymphsLib.CommonUtilities.Extensions;
using NymphsLib.CommonUtilities.FileSystem;
using MovieBrowser.Event;
using MovieBrowser.Model;
using MovieBrowser.Parser;
using MovieBrowser.Presentation.Events;
using MovieBrowser.Util;
using OfficeOpenXml;
using NymphsLib.ShellLib;
using NavigateEventArgs = MovieBrowser.Event.NavigateEventArgs;

namespace MovieBrowser.Controller
{
    public class MovieBrowserController : IDebugLogEvent
    {
        #region Private Variables
        private MovieDbEntities _entities;
        #endregion

        #region Properties
        public MovieDbEntities Db { get { return _entities; } }
        #endregion

        public MovieBrowserController(MovieBrowserController @this = null)
        {
            try
            {
                _entities = new MovieDbEntities();
                if (@this != null)
                {
                    DebugText = @this.DebugText;
                    OnMovieInformationCollected = @this.OnMovieInformationCollected;
                    OnNavigate = @this.OnNavigate;
                    OnNotificationFired = @this.OnNotificationFired;
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
                Logger.Exception(exception, 43);
            }
        }

        #region Event
        public event EventHandler DebugText;
        public void InvokeOnDebugText(Exception exception)
        {
            var handler = DebugText;
            if (handler != null) handler(this, new DebugTextEventArgs(exception));
        }
        public void InvokeOnDebugText(string text)
        {
            var handler = DebugText;
            if (handler != null) handler(this, new DebugTextEventArgs(text));
        }

        public event EventHandler OnMovieInformationCollected;
        public void InvokeOnMovieInformationCollected(Movie movie, string message)
        {
            var handler = OnMovieInformationCollected;
            if (handler != null) handler(this, new MovieEventArgs(movie, message));
        }

        public event EventHandler OnNotificationFired;
        private void InvokeOnNotificationFired(string text)
        {
            var handler = OnNotificationFired;
            if (handler != null) handler(this, new DebugTextEventArgs(text));
        }

        public event EventHandler OnNavigate;
        public void InvokeOnNavigate(NavigateEventArgs e)
        {
            var handler = OnNavigate;
            if (handler != null) handler(this, e);
        }

        #endregion

        #region Constants
        public const string GoogleSearch = "http://www.google.com/search?q=";
        public const string ImdbSearch = "http://www.imdb.com/find?s=all&q=";
        public const string ImdbTitle = "http://www.imdb.com/title/";
        public const string ImdbKeywordUrl = "http://www.imdb.com/title/{0}/keywords";
        public const string ImdbName = "http://www.imdb.com/name/";
        #endregion

        public bool RecentSearch { get; set; }

        public bool IntelligentSearch { get; set; }

        public IEnumerable<Movie> Movies
        {
            get
            {
                return Db.Movies.ToList();
            }
        }

        public void SearchMovieTree(string address, OLVListItem movie)
        {
            try
            {
                SearchMovie(address, (Movie)movie.RowObject);
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
                Logger.Exception(exception, 134);
            }
        }

        public void SearchMovie(string address, Movie movie)
        {
            try
            {
                RecentSearch = true;
                if (address.Equals(ImdbSearch) && movie != null && !string.IsNullOrEmpty(movie.ImdbId))
                {

                    Navigate(ImdbTitle + movie.ImdbId);
                }
                else
                {
                    if (movie != null) Navigate(address + HttpHelper.UrlEncode(IgnoreWords(movie.Title)));
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception); Logger.Exception(exception, 116);
            }
        }

        public static string IgnoreWords(string text)
        {
            text = text.ToLower();
            var ignored = Properties.Settings.Default.IgnoreWords.ToLower().Split();
            text = ignored.Aggregate(text, (current, s) => string.IsNullOrEmpty(s) ? current : current.Replace(s, ""));
            text = text.Replace(".", " ");
            return text;
        }

        public static string ChangeFolderName(Movie original)
        {
            var newdir = original.FilePath.Substring(0, original.FilePath.LastIndexOf("\\", StringComparison.Ordinal) + 1);
            newdir += original.FolderName.CleanFileName();

            if (original.FilePath != newdir && Directory.Exists(original.FilePath))
                Directory.Move(original.FilePath, newdir);

            return newdir;
        }

        public bool MovieExists(Movie movie)
        {
            if (movie == null) return false;
            return _entities.Movies.Any(o => o.ImdbId == movie.ImdbId);
        }



        public static string UpdateIgnoreWords()
        {
            var words = Properties.Settings.Default.IgnoreWords.ToLower().Split();

            var t = (from s in words
                     orderby s descending
                     select s).ToArray();

            var s2 = string.Join(" ", t);

            Properties.Settings.Default.IgnoreWords = s2;
            Properties.Settings.Default.Save();

            return s2;
        }

        public static void SaveFolderListTree(ArrayList movieFolderTree)
        {
            Properties.Settings.Default.Paths = new StringCollection();

            foreach (Movie node in movieFolderTree)
            {
                Properties.Settings.Default.Paths.Add(node.FilePath);
            }
            Properties.Settings.Default.Save();
        }

        public static void ExplorerOpen(string path)
        {
            var execute = new ShellExecute
            {
                Verb = ShellExecute.OpenFile,
                Path = path
            };
            execute.Execute();
        }

        void Navigate(string url)
        {
            InvokeOnNavigate(new NavigateEventArgs(url));
        }

        public void Redirect(string srcurl, string src)
        {
            var title = ImdbParser.ParseStringContent(src, ImdbParser.KEY_MediaFrom);
            if (!string.IsNullOrEmpty(title))
            {
                var url = "http://www.imdb.com/title/" + title;
                InvokeOnDebugText(string.Format("Redirect to '{0}'...", url));
                InvokeOnNavigate(new NavigateEventArgs(url, false));

                RecentSearch = false;
            }

            if (srcurl.StartsWith(ImdbSearch))
                RecentSearch = false;
        }

        public static void LoadPenDrives(ToolStripComboBox tsPendrives)
        {
            tsPendrives.Items.Clear();

            var ss = FileHelper.UsbDrives();
            foreach (var t in ss)
            {
                tsPendrives.Items.Add(t);
            }
            if (ss.Count > 0) tsPendrives.SelectedIndex = 0;
        }

        public static void SendTo(IEnumerable<Movie> movies, string path, OverwritePolicy overwritePolicy, bool move = false)
        {
            try
            {
                IEnumerable<Movie> enumerable = movies as IList<Movie> ?? movies.ToList();
                if (!enumerable.Any()) return;

                var movies2Copy = enumerable.Select(movie => new CopyFileInfo
                {
                    ImdbId = movie.ImdbId,
                    Title = movie.Title,
                    SourcePath = movie.FilePath,
                    TargetPath = Path.Combine(path, movie.FolderName)
                }).ToList();

                var stt2 = new SendToThread { Movies = movies2Copy, Move = move };
                stt2.SendTo(overwritePolicy);

            }
            catch (Exception exception)
            {
                //InvokeOnDebugText(exception);
                MessageBox.Show(string.Format("SendTo:\r\n{0}", exception.Message));
            }
        }

        public static void MoveTo(IEnumerable<Movie> movies, string path, bool move = false)
        {
            try
            {
                IEnumerable<Movie> enumerable = movies as IList<Movie> ?? movies.ToList();
                if (!enumerable.Any())
                    return;

                var movies2Copy = enumerable.Select(movie => new CopyFileInfo
                {
                    ImdbId = movie.ImdbId,
                    Title = movie.Title,
                    SourcePath = movie.FilePath,
                    TargetPath = Path.Combine(path, movie.FolderName)
                }).ToList();
                //                foreach (var stt in movies.Select(movie => new SendToThread { Source = movie.FilePath, Destination = Path.Combine(tsPendrives.SelectedItem.ToString(), movie.FolderName) }))

                var stt2 = new SendToThread { Movies = movies2Copy, Move = move };
                stt2.MoveTo();

            }
            catch (Exception exception)
            {
                //InvokeOnDebugText(exception);
                MessageBox.Show(string.Format("SendTo:\r\n{0}", exception.Message));
            }
        }

        public Movie CollectAndAddMovieToDb(Movie rowMovie, string html = null, bool collectKeyword = true)
        {
            try
            {
                if (string.IsNullOrEmpty(html))
                {
                    InvokeOnNotificationFired("Started collecting movie: " + rowMovie.Title);
                    html = HttpHelper.FetchWebPage(ImdbTitle + rowMovie.ImdbId);
                }

                if (string.IsNullOrEmpty(html)) return null;

                var parseMovieInfo = ImdbParserHelper.ToMovie(ImdbParser.ParseMovie(html));
                if (parseMovieInfo == null) return null;

                parseMovieInfo.FilePath = rowMovie == null ? "" : rowMovie.FilePath;

                var movie = UpdateMovie(parseMovieInfo);
                movie.ModificationDate = DateTime.Today;
                if (collectKeyword)
                {
                    CollectKeywords(parseMovieInfo);
                    movie.IsUpdated = true;
                }

                InvokeOnNotificationFired("Finished collecting movie: " + movie.Title);
                Db.SaveChanges();

                UpdateMovieNode(rowMovie, movie);

                return parseMovieInfo;
            }
            catch (Exception)
            {

                return null;
            }
        }

        public Movie UpdateMovie(Movie parseMovieInfo)
        {
            try
            {
                var movie = Db.Movies.FirstOrDefault(o => o.ImdbId == parseMovieInfo.ImdbId);
                if (movie == null)
                {
                    movie = parseMovieInfo;
                    movie.IsUpdated = false;
                    Db.AddToMovies(movie);
                    Db.SaveChanges();
                }
                else
                {
                    movie.CloneFromMovie(parseMovieInfo);
                    Db.SaveChanges();
                }

                //Add Genre
                foreach (var g in parseMovieInfo.Genres)
                {
                    var genre = GetGenre(g);
                    var movieGenre = Db.MovieGenres.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Genre.Id == genre.Id);

                    if (movieGenre != null) continue;
                    movieGenre = new MovieGenre { Movie = movie, Genre = genre };
                    Db.AddToMovieGenres(movieGenre);
                    Db.SaveChanges();
                }

                //Add Languages
                foreach (var g in parseMovieInfo.Languages)
                {
                    var language = GetLanguage(g);
                    var movieLanguage = Db.MovieLanguages.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Language.Id == language.Id);

                    if (movieLanguage != null) continue;
                    movieLanguage = new MovieLanguage { Movie = movie, Language = language };
                    Db.AddToMovieLanguages(movieLanguage);
                    Db.SaveChanges();
                }

                //Add Countries
                foreach (var g in parseMovieInfo.Countries)
                {
                    var country = GetCountry(g);
                    var movieCountry = Db.MovieCountries.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Country.Id == country.Id);

                    if (movieCountry != null) continue;
                    movieCountry = new MovieCountry { Movie = movie, Country = country };
                    Db.AddToMovieCountries(movieCountry);
                    Db.SaveChanges();
                }

                //Add Directors
                foreach (var g in parseMovieInfo.PersonDirectors)
                {
                    var person = GetPerson(g);
                    var director = Db.Directors.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Person.Id == person.Id);

                    if (director != null)
                    {
                        person.WorksAsDirector = WorksCountAsDirector(person.Id);
                        Db.SaveChanges();
                        continue;
                    }
                    director = new Director { Movie = movie, Person = person };
                    Db.AddToDirectors(director);
                    Db.SaveChanges();
                }

                //Remove Existing Stars
                var stars = Db.Stars.Where(o => o.Movie.Id == movie.Id);
                foreach (var star in stars)
                {
                    Db.DeleteObject(star);
                    Db.SaveChanges();
                }


                //Add Stars
                foreach (var g in parseMovieInfo.PersonStars)
                {
                    var person = GetPerson(g);
                    var star = Db.Stars.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Person.Id == person.Id);

                    if (star != null)
                    {
                        Db.SaveChanges();
                        continue;
                    }
                    star = new Star { Movie = movie, Person = person };
                    Db.AddToStars(star);
                    Db.SaveChanges();
                }

                //Add Parsed Actors
                foreach (var g in parseMovieInfo.PersonActors)
                {
                    var person = GetPerson(g.Person);
                    var actor = Db.Actors.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Person.Id == person.Id);

                    if (actor != null)
                    {
                        actor.CharacterId = g.CharacterId;
                        actor.CharacterName = g.CharacterName;
                        person.WorksAsActor = WorksCountAsActor(person.Id);
                        Db.SaveChanges();
                        continue;
                    }
                    actor = new Actor { Movie = movie, Person = person, CharacterName = g.CharacterName, CharacterId = g.CharacterId };
                    Db.AddToActors(actor);
                    Db.SaveChanges();
                }

                //Add Missing Stars as Actor
                foreach (var person in Db.Stars.Where(o => o.Movie.Id == movie.Id).Select(o => o.Person).ToList())
                {
                    var found = Db.Actors.Where(o => o.Movie.Id == movie.Id).Select(o => o.Person).ToList().Any(actor => actor != null && actor.Id == person.Id);

                    if (!found)
                    {
                        InvokeOnDebugText("Movie " + movie.Title + ", Actor " + person.Name);
                        var actor = new Actor { Person = person, Movie = movie };
                        person.WorksAsActor = WorksCountAsActor(person.Id);
                        Db.AddToActors(actor);
                        Db.SaveChanges();
                    }

                }

                //Add Writers
                foreach (var g in parseMovieInfo.PersonWriters)
                {
                    var person = GetPerson(g);
                    var writer = Db.Writers.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Person.Id == person.Id);

                    if (writer != null)
                    {
                        person.WorksAsWriter = WorksCountAsWriter(person.Id);
                        Db.SaveChanges();
                        continue;
                    }
                    writer = new Writer { Movie = movie, Person = person };
                    Db.AddToWriters(writer);
                    Db.SaveChanges();
                }
                return movie;
            }
            catch (Exception exp)
            {
                InvokeOnDebugText(exp);
                return null;
            }
        }

        public void UpdateMovieNode(Movie rowMovie, Movie parsedMovie)
        {
            if (parsedMovie == null)
                return;

            //UpdateMovie(parsedMovie);

            try
            {
                if (rowMovie != null)
                {
                    if (!rowMovie.IsValidMovie || parsedMovie.ImdbId == rowMovie.ImdbId)
                    {
                        if (!parsedMovie.IsVirtual && Directory.Exists(rowMovie.FilePath))
                        {
                            parsedMovie.FilePath = rowMovie.FilePath;
                            parsedMovie.FilePath = ChangeFolderName(parsedMovie);
                        }
                        rowMovie.CloneFromMovie(parsedMovie);
                    }
                    InvokeOnDebugText("Movie: " + rowMovie.Title + " is updated.");
                    InvokeOnNotificationFired("Movie: " + rowMovie.Title + " is updated.");
                }
                else
                {

                    UpdateMovie(parsedMovie);
                    InvokeOnDebugText("Movie: " + parsedMovie.Title + " is updated.");
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
                Logger.Exception(exception, 2);
            }
        }

        private Person GetPerson(Person g)
        {
            var person = Db.People.FirstOrDefault(o => o.ImdbId == g.ImdbId);

            try
            {
                if (person == null)
                {
                    person = new Person { Name = g.Name, ImdbId = g.ImdbId };
                    Db.AddToPeople(person);
                    Db.SaveChanges();
                }
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message + "\n" + g.Name + "\n" + exp.InnerException, g.Name + " " + g.ImdbId);
            }

            return person;
        }

        private Keyword GetKeyword(Keyword g)
        {
            var keyword = Db.Keywords.FirstOrDefault(o => o.Code == g.Code);
            if (keyword == null)
            {
                keyword = new Keyword { Name = g.Name, Code = g.Code };
                Db.AddToKeywords(keyword);
                Db.SaveChanges();
            }
            return keyword;
        }

        private Country GetCountry(Country c)
        {
            var country = Db.Countries.FirstOrDefault(o => o.Code == c.Code);
            if (country == null)
            {
                country = new Country { Name = c.Name, Code = c.Code };
                Db.AddToCountries(country);
                Db.SaveChanges();
            }
            return country;
        }

        private Language GetLanguage(Language l)
        {
            var language = Db.Languages.FirstOrDefault(o => o.Code == l.Code);
            if (language == null)
            {
                language = new Language { Name = l.Name, Code = l.Code };
                Db.AddToLanguages(language);
                Db.SaveChanges();
            }
            return language;
        }

        private Genre GetGenre(Genre g)
        {
            var genre = Db.Genres.FirstOrDefault(o => o.Code == g.Code);
            if (genre == null)
            {
                genre = new Genre { Name = g.Name, Code = g.Code, Rated = 0 };
                Db.AddToGenres(genre);
                Db.SaveChanges();
            }
            return genre;
        }

        public void RemoveMovie(string imdbId)
        {

            Db.DeleteObjects(Db.MovieGenres.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.MovieCountries.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.MovieKeywords.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.MovieLanguages.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.MoviePersonalNotes.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.MovieUserLists.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.Stars.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.Directors.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.Writers.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.MovieFilesystems.Where(o => o.Movie.ImdbId == imdbId));
            Db.DeleteObjects(Db.Actors.Where(o => o.Movie.ImdbId == imdbId));

            Db.DeleteObjects(Db.Movies.Where(o => o.ImdbId == imdbId));


            Db.SaveChanges();
        }

        private MoviePersonalNote GetNote(MovieDbEntities db, User loggedInUser, Movie rowMovie)
        {
            try
            {
                var user = db.Users.FirstOrDefault(o => o.Username == loggedInUser.Username);
                var movie = db.Movies.FirstOrDefault(o => o.ImdbId == rowMovie.ImdbId);

                if (movie == null)
                {
                    rowMovie.IsUpdated = false;
                    db.AddToMovies(rowMovie);
                    movie = rowMovie;
                }

                var personalNote = db.MoviePersonalNotes.FirstOrDefault(o => o.User.Id == loggedInUser.Id && o.Movie.Id == movie.Id);

                if (personalNote == null)
                {
                    personalNote = new MoviePersonalNote { Comment = "", Movie = movie, User = user };
                    db.AddToMoviePersonalNotes(personalNote);
                }
                return personalNote;
            }
            catch (Exception exp)
            {
                InvokeOnDebugText(exp);
                Logger.Exception(exp, 550);
                return null;
            }
        }

        public MoviePersonalNote UpdateUserRating(User loggedInUser, Movie rowMovie, double rating)
        {
            if (rowMovie == null) return null;
            var note = GetNote(Db, loggedInUser, rowMovie);
            note.Rating = rating;
            Db.SaveChanges();
            return note;
        }

        public MoviePersonalNote ToggleOrSetWishlist(User loggedInUser, Movie rowMovie, bool? value = null)
        {
            var note = GetNote(Db, loggedInUser, rowMovie);
            if (value != null)
                note.Wishlist = value.Value;
            else
                note.Wishlist = !note.Wishlist;
            rowMovie.Watchlist = note.Wishlist;
            Db.SaveChanges();
            return note;
        }
        public MoviePersonalNote SetFavourite(User loggedInUser, Movie rowMovie, bool like, int? value = null)
        {
            var note = GetNote(Db, loggedInUser, rowMovie);
            if (value == null)
                note.Favourite = like ? (note.Favourite > 0 ? 0 : 1) : (note.Favourite < 0 ? 0 : -1);
            else
            {
                note.Favourite = value.Value;
            }
            Db.SaveChanges();
            return note;
        }
        public MoviePersonalNote ToggleOrSetSeenIt(User loggedInUser, Movie rowMovie, bool? val = null)
        {
            var note = GetNote(Db, loggedInUser, rowMovie);
            note.Seen = val ?? !note.Seen;
            rowMovie.Seen = note.Seen;
            Db.SaveChanges();
            return note;
        }
        public MoviePersonalNote ToggleOrSetHaveIt(User loggedInUser, Movie rowMovie, bool? val = null)
        {
            var note = GetNote(Db, loggedInUser, rowMovie);
            note.Have = val ?? !note.Have;
            rowMovie.Have = note.Have;
            Db.SaveChanges();
            return note;
        }

        public void AddToUserList(Movie rowMovie, long listId)
        {
            var movie = Db.Movies.FirstOrDefault(o => o.ImdbId == rowMovie.ImdbId);

            var list = Db.UserLists.FirstOrDefault(o => o.Id == listId);
            if (list == null) return;

            var alreadyadded = Db.MovieUserLists.FirstOrDefault(o => o.UserList.Id == listId && o.Movie.ImdbId == rowMovie.ImdbId);
            if (alreadyadded == null)
            {
                var a = new MovieUserList { UserList = list, Movie = movie };
                Db.AddToMovieUserLists(a);
                Db.SaveChanges();
            }
        }

        public void RemoveFromUserList(Movie movie, long listId)
        {
            var alreadyadded = Db.MovieUserLists.FirstOrDefault(o => o.UserList.Id == listId && o.Movie.ImdbId == movie.ImdbId);
            if (alreadyadded == null) return;
            Db.DeleteObject(alreadyadded);
            Db.SaveChanges();
        }

        public MoviePersonalNote RateIt(User loggedInUser, Movie rowMovie, double rating)
        {
            var note = GetNote(Db, loggedInUser, rowMovie);
            note.Rating = rating;
            Db.SaveChanges();
            return note;
        }

        public void CollectKeywords(Movie parseMovieInfo)
        {
            if (!parseMovieInfo.IsValidMovie) return;

            var movie = Db.Movies.FirstOrDefault(o => o.ImdbId == parseMovieInfo.ImdbId) ?? UpdateMovie(parseMovieInfo);

            var keywordPage = HttpHelper.FetchWebPage(string.Format(ImdbKeywordUrl, parseMovieInfo.ImdbId));
            parseMovieInfo.Keywords = ImdbParserHelper.ToKeywords(ImdbParser.ParseKeywords(keywordPage));

            foreach (var g in parseMovieInfo.Keywords)
            {
                var keyword = GetKeyword(g);
                var movieKeyword = Db.MovieKeywords.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Keyword.Id == keyword.Id);

                if (movieKeyword != null) continue;
                movieKeyword = new MovieKeyword { Movie = movie, Keyword = keyword };
                Db.AddToMovieKeywords(movieKeyword);
                Db.SaveChanges();
            }

            if (parseMovieInfo.Keywords.Count() != 0)
            {
                movie.IsUpdated = true;
                Db.SaveChanges();
            }
        }

        public void Refresh()
        {
            _entities = new MovieDbEntities();
        }

        public void UpdateFileSystemInformation(StringCollection paths)
        {
            foreach (var directoryInfo in from string rootPath in paths select new DirectoryInfo(rootPath))
            {
                UpdateFileSystemInformation(directoryInfo);
            }
        }

        public void UpdateFileSystemInformation(List<Movie> children)
        {
            foreach (var child in children)
            {
                try
                {
                    var dir = new DirectoryInfo(child.FilePath);
                    UpdateFileSystemInformation(dir);
                }
                catch (Exception exception)
                {
                    InvokeOnDebugText(exception);
                }
            }

        }

        private void UpdateFileSystemInformation(DirectoryInfo directoryInfo)
        {
            var movie = Movie.FromFolderName(directoryInfo.FullName);

            if (movie.IsValidMovie)
            {
                var m = Db.Movies.FirstOrDefault(o => o.ImdbId == movie.ImdbId);
                if (m == null)
                {
                    m = new Movie();
                    m.CloneFromMovie(movie);
                    Db.AddToMovies(m);
                    Db.SaveChanges();
                }

                var fs = Db.MovieFilesystems.FirstOrDefault(a => a.Movie.ImdbId == movie.ImdbId &&
                                                                 a.FolderPath == directoryInfo.FullName &&
                                                                 a.ComputerName == Environment.MachineName);
                if (fs == null)
                {
                    string computername;
                    if (directoryInfo.FullName.StartsWith("\\\\"))//Network
                    {

                        computername = directoryInfo.FullName.Substring(2);
                        computername = computername.Substring(0, computername.IndexOf("\\", StringComparison.Ordinal));
                    }
                    else
                    {
                        computername = Environment.MachineName;
                    }

                    fs = new MovieFilesystem
                             {
                                 Movie = m,
                                 ComputerName = computername,
                                 FolderPath = directoryInfo.FullName
                             };

                    m.IsInCollection = true;

                    Db.AddToMovieFilesystems(fs);
                    Db.SaveChanges();
                }
            }

            foreach (var directory in directoryInfo.GetDirectories())
            {
                UpdateFileSystemInformation(directory);
            }
        }


        public void SaveToExcel(FileInfo newFile, List<Movie> movies)
        {
            var pck = new ExcelPackage(newFile);
            //Add the Content sheet
            var ws = pck.Workbook.Worksheets.Add("Movies");

            //Headers
            ws.Cells["A1"].Value = "Title";
            ws.Cells["B1"].Value = "Rating";
            ws.Cells["C1"].Value = "Year";
            ws.Cells["D1"].Value = "ImdbId";
            ws.Cells["E1"].Value = "MPAA";
            ws.Cells["F1"].Value = "Reason";
            ws.Cells["G1"].Value = "Highlight";

            for (var i = 0; i < movies.Count; i++)
            {
                var movie = movies[i];
                if (movie != null)
                {
                    ws.Cells[i + 2, 1].Value = movie.Title;
                    ws.Cells[i + 2, 2].Value = movie.Rating;
                    ws.Cells[i + 2, 3].Value = movie.Year;
                    ws.Cells[i + 2, 4].Value = movie.ImdbId;
                    ws.Cells[i + 2, 5].Value = movie.MPAA;
                    ws.Cells[i + 2, 6].Value = movie.MPAAReason;
                    ws.Cells[i + 2, 7].Value = movie.Highlight;
                }
            }
            pck.Save();
        }

        public void ImportExcel(FileInfo newFile)
        {
            var pck = new ExcelPackage(newFile);
            //Add the Content sheet
            foreach (var excelWorksheet in pck.Workbook.Worksheets)
            {
                for (var i = 2; i < Int32.MaxValue; i++)
                {
                    var value = excelWorksheet.Cells[i, 4].Value;
                    if (value == null) return;
                    var imdbId = value.ToString();
                    if (imdbId == "") return;
                    var movie = _entities.Movies.FirstOrDefault(o => o.ImdbId == imdbId);
                    if (movie == null)
                    {
                        movie = new Movie
                                    {
                                        ImdbId = imdbId,
                                        Title = excelWorksheet.Cells[i, 1].Value.ToString(),
                                        Rating = Convert.ToDouble(excelWorksheet.Cells[i, 2].Value),
                                        Year = Convert.ToInt32(excelWorksheet.Cells[i, 3].Value)
                                    };
                        _entities.AddToMovies(movie);
                        _entities.SaveChanges();
                    }
                }
            }

            //            var ws = pck.Workbook.Worksheets.Add("Movies");

            //Headers
            //            ws.Cells["A1"].Value = "Title";
            //            ws.Cells["B1"].Value = "Rating";
            //            ws.Cells["C1"].Value = "Year";
            //            ws.Cells["D1"].Value = "ImdbId";
            //            ws.Cells["E1"].Value = "MPAA";
            //            ws.Cells["F1"].Value = "Reason";
            //            ws.Cells["G1"].Value = "Highlight";

            //            for (int i = 0; i < movies.Count; i++)
            //            {
            //                var movie = movies[i];
            //                if (movie != null)
            //                {
            //                    ws.Cells[i + 2, 1].Value = movie.Title;
            //                    ws.Cells[i + 2, 2].Value = movie.Rating;
            //                    ws.Cells[i + 2, 3].Value = movie.Year;
            //                    ws.Cells[i + 2, 4].Value = movie.ImdbId;
            //                    ws.Cells[i + 2, 5].Value = movie.MPAA;
            //                    ws.Cells[i + 2, 6].Value = movie.MPAAReason;
            //                    ws.Cells[i + 2, 7].Value = movie.Highlight;
            //                }
            //            }
            //            pck.Save();
        }


        public void UpdateKeywords(IList<Movie> selectedMovies)
        {
            var information = new CollectInformation
            {
                MovieController = new MovieBrowserController(this),
                ListNodes = selectedMovies,
                FetchKeyword = true,
                UpdateNode = true,

            };
            information.OnDebugText += DebugText;
            var thread = new Thread(information.CollectKeywords);
            thread.Start();
        }

        public void UpdateInformation(IList<Movie> selectedMovies, MovieBrowserController controller, bool updateNode = false, bool fetchKeywords = false)
        {
            var information = new CollectInformation
            {
                MovieController = controller,
                ListNodes = selectedMovies,
                FetchKeyword = fetchKeywords,
                UpdateNode = updateNode
            };
            information.OnDebugText += DebugText;
            var thread = new Thread(information.CollectFullInformation);
            thread.Start();
        }

        public void UpdateNodeFromInformation(Movie node, CollectInformation information)
        {
            if (node != null) information.ListNodes = new List<Movie> { node };

            var thread = new Thread(information.CollectFullInformation);
            thread.Start();
        }

        public void SearchPerson(string address, Person person)
        {
            try
            {
                if (person != null && !string.IsNullOrEmpty(person.ImdbId))
                {
                    Navigate(address + person.ImdbId);
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception); Logger.Exception(exception, 116);
            }
        }

        public void UpdatePersonInformation(IList<Person> persons, MovieBrowserController controller = null)
        {
            if (controller == null)
                controller = this;
            var information = new CollectInformation
            {
                MovieController = controller,
                Persons = persons
            };
            information.OnDebugText += DebugText;
            var thread = new Thread(information.CollectPersonInformation);
            thread.Start();
        }

        public Person CollectAndAddPersonToDb(Person person)
        {
            var html = HttpHelper.FetchWebPage(ImdbName + person.ImdbId);
            var personInfo = ImdbParserHelper.ToPerson(ImdbParser.ParsePerson(html));
            if (personInfo == null) return null;
            return SavePerson(personInfo);
        }

        private Person SavePerson(Person personInfo)
        {
            var person = Db.People.FirstOrDefault(o => o.ImdbId == personInfo.ImdbId);
            if (person == null)
            {
                person = personInfo;
                person.CreationDate = DateTime.Now;
                person.WorksAsWriter = person.WorksAsDirector = person.WorksAsActor = 0;
                Db.AddToPeople(person);
                Db.SaveChanges();
            }
            else
            {
                person.Clone(personInfo);
                person.ModificationDate = DateTime.Now;
                UpdatePersonWorks(person);
            }
            return person;
        }

        public void UpdatePersonWorks(long personId)
        {
            var person = Db.People.FirstOrDefault(o => o.Id == personId);
            UpdatePersonWorks(person);
        }

        public void UpdatePersonWorks(string personImdbId)
        {
            var person = Db.People.FirstOrDefault(o => o.ImdbId == personImdbId);
            UpdatePersonWorks(person);
        }

        public void UpdatePersonWorks(Person person)
        {
            if (person == null) return;

            person.WorksAsActor = WorksCountAsActor(person.Id);
            person.WorksAsDirector = WorksCountAsDirector(person.Id);
            person.WorksAsWriter = WorksCountAsWriter(person.Id);
            person.Count1 = WorksCountAsStar(person.Id);
            if (person.Profession != null && person.Profession.Contains("Actress"))
                person.Gender = "Female";
            else if (person.Profession != null && person.Profession.Contains("Actor"))
                person.Gender = "Male";
            Db.SaveChanges();
        }

        private int WorksCountAsStar(long id)
        {
            return Db.Stars.Count(o => o.Person.Id == id);
        }

        public int WorksCountAsActor(long id)
        {
            return Db.Actors.Count(o => o.Person.Id == id);
        }

        public int WorksCountAsDirector(long id)
        {
            return Db.Directors.Count(o => o.Person.Id == id);
        }

        public int WorksCountAsWriter(long id)
        {
            return Db.Writers.Count(o => o.Person.Id == id);
        }

        internal void UpdateSubtitle(Movie selectedMovie, bool p)
        {
            try
            {
                var movie = Db.Movies.FirstOrDefault(m => m.ImdbId == selectedMovie.ImdbId);
                if (movie == null) return;
                var kv = Db.MovieKeyValues.FirstOrDefault(o => o.Movie.Id == movie.Id && o.Key == "Subtitle");
                if (kv == null)
                {
                    kv = new MovieKeyValue { Movie = movie, Key = "Subtitle" };
                    Db.AddToMovieKeyValues(kv);
                }
                kv.Value = p ? "True" : "False";
                Db.SaveChanges();
            }
            catch
            {
                Console.Write("123456789");
            }
        }
    }
}
